package com.cupk.rotaryguard.monitor.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cupk.common.base.config.Contant;
import com.cupk.common.base.utils.result.Result;
import com.cupk.common.base.utils.result.ResultGenerator;
import com.cupk.rotaryguard.monitor.entity.DeviceDiagnosis;
import com.cupk.rotaryguard.monitor.entity.DeviceInfo;
import com.cupk.rotaryguard.monitor.entity.DeviceMonitorRecord;
import com.cupk.rotaryguard.monitor.entity.WarningInfo;
import com.cupk.rotaryguard.monitor.mapper.DeviceMapper;
import com.cupk.rotaryguard.monitor.mapper.DiagnosisMapper;
import com.cupk.rotaryguard.monitor.mapper.MonitorRecordMapper;
import com.cupk.rotaryguard.monitor.service.DiagnosisService;
import com.cupk.rotaryguard.monitor.utils.ClassificationModel;
import com.cupk.rotaryguard.monitor.utils.CsvUtil;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.*;

import static com.cupk.rotaryguard.monitor.controller.flask.FlaskHttpClient.*;
import static com.cupk.rotaryguard.monitor.controller.flask.FlaskHttpClient.selectAllFeature;
import static com.cupk.rotaryguard.monitor.utils.CsvUtil.deleteFileContent;
import static com.cupk.rotaryguard.monitor.utils.GenrateFeatureData.getValuesFromDiagnosisDeviceProb;

/**
 * @author tjy
 * @date 2023/4/13
 * @apiNote
 */
@Service
public class DiagnosisServiceImpl extends ServiceImpl<DiagnosisMapper, DeviceDiagnosis>
        implements DiagnosisService {
    @Resource
    private DeviceMapper deviceMapper;
    @Resource
    private MonitorRecordMapper monitorRecordMapper;
    @Resource
    private DiagnosisMapper diagnosisMapper;
    private static final Logger log = LoggerFactory.getLogger(DiagnosisServiceImpl.class);

    @Override
    public Result diagnosisDevice(Long deviceId) {
        DeviceInfo curDevice = deviceMapper.selectById(deviceId);
        String deviceModel = curDevice.getDeviceModel();
        DeviceDiagnosis diagnosisRecord = new DeviceDiagnosis();

        //插入诊断表数据
        diagnosisRecord.setDeviceId(deviceId);
        diagnosisRecord.setDeviceModel(deviceModel);

        //获取指定设备号前3500条数据作为诊断数据
        QueryWrapper<DeviceMonitorRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("device_id", deviceId)
                .orderByDesc("record_time")
                .last("limit 0,3500");
        List<DeviceMonitorRecord> monitorRecords = monitorRecordMapper.selectList(queryWrapper);
        List<String[]> recordList = new ArrayList<>();
        for (DeviceMonitorRecord curRecord : monitorRecords) {
            String[] record = new String[3];
            record[0] = String.valueOf(curRecord.getDeTime());
            record[1] = String.valueOf(curRecord.getFeTime());
            record[2] = String.valueOf(curRecord.getRpm());
            recordList.add(record);
        }
        CsvUtil.writeCsvFile(recordList, Contant.TEST_FILE_PATH);
        //调用flask接口进行特征提取
        try {
            testCSVToTestTW();
            testTWtoTestGena();
            getAllFeatureCSV();
            selectAllFeature();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        //将特征提取到的文件转换为String[][]
        String featureFilePath = Contant.FEATURE_SELECT_FILE_PATH;
        String[][] features = CsvUtil.readCSV(featureFilePath, false);
        //开始诊断
        //结果
        String diagnosisRes = null;
        try {
            diagnosisRes = ClassificationModel.diagnosis(features);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        //概率分布
        String probDistribution = null;
        try {
            probDistribution = ClassificationModel.diagnosisPredictProb(features);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        //插入诊断表数据
        diagnosisRecord.setDeviceId(deviceId);
        diagnosisRecord.setDeviceModel(deviceModel);
        diagnosisRecord.setDiagnosisRes(diagnosisRes);
        diagnosisRecord.setProbDistribution(probDistribution);
        //更新诊断表
        diagnosisMapper.insert(diagnosisRecord);

        //清空文件内容
        try {
            File file1 = new File(Contant.TEST_FILE_PATH);
            File file2 = new File(Contant.TEST_TW_FILE_PATH);
            File file3 = new File(Contant.FEATURE_FILE_PATH);
            File file4 = new File(Contant.FEATURE_SELECT_FILE_PATH);
            deleteFileContent(file1);
            deleteFileContent(file2);
            deleteFileContent(file3);
            deleteFileContent(file4);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return ResultGenerator.genSuccessResult(diagnosisRes, "诊断成功，诊断结果为:" + diagnosisRes);
    }

    /**
     * 概率分布预测
     *
     * @param deviceId
     * @return
     */
    @Override
    public Result diagnosisDeviceProb(Long deviceId) {
        DeviceInfo curDevice = deviceMapper.selectById(deviceId);
        String deviceModel = curDevice.getDeviceModel();
        DeviceDiagnosis diagnosisRecord = new DeviceDiagnosis();

        //插入诊断表数据
        diagnosisRecord.setDeviceId(deviceId);
        diagnosisRecord.setDeviceModel(deviceModel);

        //获取指定设备号前3500条数据作为诊断数据
        QueryWrapper<DeviceMonitorRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("device_id", deviceId)
                .orderByDesc("record_time")
                .last("limit 0,3500");
        List<DeviceMonitorRecord> monitorRecords = monitorRecordMapper.selectList(queryWrapper);
        List<String[]> recordList = new ArrayList<>();
        for (DeviceMonitorRecord curRecord : monitorRecords) {
            String[] record = new String[3];
            record[0] = String.valueOf(curRecord.getDeTime());
            record[1] = String.valueOf(curRecord.getFeTime());
            record[2] = String.valueOf(curRecord.getRpm());
            recordList.add(record);
        }
        CsvUtil.writeCsvFile(recordList, Contant.TEST_FILE_PATH);
        //调用flask接口进行特征提取
        try {
            log.info(testCSVToTestTW());
            log.info(testTWtoTestGena());
            log.info(getAllFeatureCSV());
            log.info(selectAllFeature());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        //将特征提取到的文件转换为String[][]
        String featureFilePath = Contant.FEATURE_SELECT_FILE_PATH;
        String[][] features = CsvUtil.readCSV(featureFilePath, false);
        //开始诊断
        //结果
        String diagnosisRes = null;
        try {
            diagnosisRes = ClassificationModel.diagnosis(features);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        //概率分布
        String probDistribution = null;
        try {
            probDistribution = ClassificationModel.diagnosisPredictProb(features);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        //插入诊断表数据
        diagnosisRecord.setDeviceId(deviceId);
        diagnosisRecord.setDeviceModel(deviceModel);
        diagnosisRecord.setDiagnosisRes(diagnosisRes);
        diagnosisRecord.setProbDistribution(probDistribution);
        //更新诊断表
        diagnosisMapper.insert(diagnosisRecord);

        File file1 = null;
        File file2 = null;
        File file3 = null;
        File file4 = null;
        //清空文件内容
        try {
            file1 = new File(Contant.TEST_FILE_PATH);
            file2 = new File(Contant.TEST_TW_FILE_PATH);
            file3 = new File(Contant.FEATURE_FILE_PATH);
            file4 = new File(Contant.FEATURE_SELECT_FILE_PATH);
        } catch (Exception e) {
            log.error(e.getMessage());
        } finally {
            deleteFileContent(file1);
            deleteFileContent(file2);
            deleteFileContent(file3);
            deleteFileContent(file4);
        }
        if (StringUtils.isEmpty(probDistribution)) {
            return ResultGenerator.genFailResult(null, "诊断失败，请联系管理员！");
        }
        Map<Integer, Double> valuesFromDiagnosisDeviceProb = getValuesFromDiagnosisDeviceProb(probDistribution);
        return ResultGenerator.genSuccessResult(valuesFromDiagnosisDeviceProb, "诊断成功，诊断结果为：" + diagnosisRes);
    }

    /**
     * 获取故障中的设备数量
     *
     * @return
     */
    @Override
    public Result getFaultDeviceCount() {
        int count = 0;
        QueryWrapper<DeviceDiagnosis> diagnosisQueryWrapper = new QueryWrapper<>();
        List<DeviceInfo> devices = deviceMapper.selectList(null);
        for (DeviceInfo device : devices) {
            diagnosisQueryWrapper.clear();
            diagnosisQueryWrapper.eq("device_id", device.getId())
                    .orderByDesc("diagnosis_time")
                    .last("limit 1");
            DeviceDiagnosis deviceDiagnoses = diagnosisMapper.selectOne(diagnosisQueryWrapper);
            if (!ObjectUtils.isEmpty(deviceDiagnoses)) {
                String diagnosisRes = deviceDiagnoses.getDiagnosisRes();
                if (!diagnosisRes.equals("正常")) {
                    count++;
                }
            }
        }
        return ResultGenerator.genSuccessResult(count, "当前处于故障中的设备数量为：" + count);
    }

    /**
     * 根据设备号获取最新10条诊断记录
     *
     * @param deviceId
     * @return
     */
    @Override
    public Result getLastTenDiagnosisRecord(Long deviceId) {
        QueryWrapper<DeviceDiagnosis> diagnosisQueryWrapper = new QueryWrapper<>();
        diagnosisQueryWrapper.eq("device_id", deviceId)
                .orderByDesc("diagnosis_time")
                .last("limit 0,10");
        List<DeviceDiagnosis> curDeviceLastTenRecords = diagnosisMapper.selectList(diagnosisQueryWrapper);
        List<Map<Integer, Double>> proList = new ArrayList<>();
        for (DeviceDiagnosis diagnosis : curDeviceLastTenRecords) {
            proList.add(getValuesFromDiagnosisDeviceProb(diagnosis.getProbDistribution()));
        }
        return ResultGenerator.genSuccessResult(proList, "获取成功");
    }

    /**
     * 获取诊断记录
     *
     * @param pageSize
     * @param pageNum
     * @param deviceId
     * @param deviceModel
     * @param diagnosisRes
     * @return
     */
    @Override
    public Result getDiagnosisRecord(Integer pageSize, Integer pageNum,
                                     Long deviceId, String deviceModel,
                                     String diagnosisRes) {
        QueryWrapper<DeviceDiagnosis> diagnosisQueryWrapper = new QueryWrapper<>();
        if (null != deviceId) {
            diagnosisQueryWrapper.eq("device_id", deviceId);
        }
        diagnosisQueryWrapper.like("device_model", deviceModel);
        diagnosisQueryWrapper.like("diagnosis_res", diagnosisRes);
        diagnosisQueryWrapper.orderByDesc("diagnosis_time");
        IPage<DeviceDiagnosis> pageData = new Page<>(pageNum, pageSize);
        IPage<DeviceDiagnosis> diagnosisIPage = diagnosisMapper.selectPage(pageData, diagnosisQueryWrapper);
        return ResultGenerator.genSuccessResult(diagnosisIPage, "查询成功");
    }

    /**
     * 单个删除
     *
     * @param id
     * @return
     */
    @Override
    public Result delDiagnosisRecord(Long id) {
        diagnosisMapper.deleteById(id);
        return ResultGenerator.genSuccessResult(id, "删除成功,id为" + id);

    }

    /**
     * 批量删除
     *
     * @param ids
     * @return
     */
    @Override
    public Result delDiagnosisRecords(List<Long> ids) {
        diagnosisMapper.deleteBatchIds(ids);
        return ResultGenerator.genSuccessResult(null, "删除成功,id为:" + Arrays.toString(ids.toArray()));
    }
}
